#!/usr/local/bin/perl -w
#+------------------------------------------------------------------------------
#|
#| FILENAME: cairointf.pm
#|
#| PROJECT: Cairolib
#|
#| FILE DESCRIPTION:
#|    The following file contains a generic wrapper around the cairo library
#|
#+------------------------------------------------------------------------------
#|
#| Cairolib is a series of extensions, examples, and libraries for the
#| Cairo graphics package (see http://www.cairographics.org).
#| 
#| Copyright (C) 2006  Bradford Elliott
#|
#| This library is free software; you can redistribute it and/or
#| modify it under the terms of the GNU Lesser General Public
#| License as published by the Free Software Foundation; either
#| version 2.1 of the License, or (at your option) any later version.
#| 
#| This library is distributed in the hope that it will be useful,
#| but WITHOUT ANY WARRANTY; without even the implied warranty of
#| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#| Lesser General Public License for more details.
#| 
#| You should have received a copy of the GNU Lesser General Public
#| License along with this library; if not, write to the Free Software
#| Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
#| 
#+------------------------------------------------------------------------------

package cairolib::cairointf;
use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION);
use warnings;
use strict;
use POSIX;
use Exporter;
use lib ".";
use cairolib::cairolib;

$VERSION = 1.00;              # Or higher
@ISA = qw(Exporter);

@EXPORT = qw ();

use constant EOL => "\r\n";

#+-----------------------------------------------------------------------------
#|
#| NAME:
#|    new()
#|
#| SYNOPSIS:
#|    new();
#|
#| PARAMETERS:
#|    None.
#|
#| FUNCTION:
#|    This is the constructor for the cairo document library
#|
#| RETURNS:
#|    A pointer to an instance of the cairo document.
#|
#| NOTES:
#|    None.
#|
#+-----------------------------------------------------------------------------
sub new
{
    my $that = shift;
    my $class = ref($that) || $that;
    
    my $width  = $_[0];
    my $height = $_[1];
    
    my $cairo = new cairolib::cairolib_t($width, $height);
    
    $cairo->rectangle(0, 0, $width, $height);
    $cairo->set_source_rgb(1, 1, 1);
    $cairo->fill();
    
    
    my $uniqueId = 1;
    
    # Setup the class members
    my $self = {IMAGE =>  \$cairo,
                WIDTH =>  \$width,
                HEIGHT => \$height,
                DOCUNIQUEIDS => \$uniqueId};
    
    bless($self, $class);
    
    return $self;
}


#+-----------------------------------------------------------------------------
#|
#| NAME:
#|    DESTROY
#|
#| SYNOPSIS:
#|    DESTROY()
#|
#| PARAMETERS:
#|    None.
#|
#| FUNCTION:
#|    This is the destructor for the cairo document which is called
#|    automatically by the perl interpreter when the instance of the
#|    class is no longer in scope.
#|
#| RETURNS:
#|    None.
#|
#| NOTES:
#|    None.
#|
#+-----------------------------------------------------------------------------
sub DESTROY
{
    my $self = shift;
}


#+----------------------------------------------------------------------------
#|
#| FUNCTION: defaultProperty()
#|
#| DESCRIPTION:
#|   
#|
#| PARAMETERS:
#|   
#|
#| RETURNS:
#|   
#|     
#+----------------------------------------------------------------------------
sub defaultProperty
{
    my $propsRef = $_[0];
    my $prop     = $_[1];
    my $default  = $_[2];
    
    if(!defined($propsRef->{$prop}))
    {
        $propsRef->{$prop} = $default;
    }
}


#+----------------------------------------------------------------------------
#|
#| FUNCTION: anyId()
#|
#| DESCRIPTION:
#|   This method simply generates a Unique ID for an shape within the cairo
#|   document. It uses the DOCUNIQUEIDS field in the class to store the
#|   the most recently issued unique ID.
#|
#| PARAMETERS:
#|   $self (I) - The pointer to the blessed class instance.
#|
#| RETURNS:
#|   A unique ID to assign to the shape.
#|     
#+----------------------------------------------------------------------------
sub anyId
{
    my $self = shift;
    
    my $id = $self->{DOCUNIQUEIDS};
    
    ${$self->{DOCUNIQUEIDS}} += 1;
    
    return ${$id};
}


#+-----------------------------------------------------------------------------
#|
#| NAME:
#|    setHeight()
#|
#| SYNOPSIS:
#|    ;
#|
#| PARAMETERS:
#|    None.
#|
#| FUNCTION:
#|    
#|
#| RETURNS:
#|    
#|
#+-----------------------------------------------------------------------------
sub setHeight
{
    my $self = shift;
    ${$self->{HEIGHT}} = $_[0];
}


#+-----------------------------------------------------------------------------
#|
#| NAME:
#|    setWidth()
#|
#| SYNOPSIS:
#|    ;
#|
#| PARAMETERS:
#|    None.
#|
#| FUNCTION:
#|    
#|
#| RETURNS:
#|    
#|
#+-----------------------------------------------------------------------------
sub setWidth
{
    my $self = shift;
    ${$self->{WIDTH}} = $_[0];
}


#+-----------------------------------------------------------------------------
#|
#| NAME:
#|    translateColor()
#|
#| SYNOPSIS:
#|    ;
#|
#| PARAMETERS:
#|    None.
#|
#| FUNCTION:
#|    
#|
#| RETURNS:
#|    
#|
#+-----------------------------------------------------------------------------
sub translateColor
{
    my $color = uc($_[0]);
    my @color_array;
    
    if($color eq "BLUE")
    {
        @color_array = (0,0,1);
    }
    elsif($color eq "RED")
    {
        @color_array = (1,0,0);
    }
    elsif($color eq "GREEN")
    {
        @color_array = (0,1,0);
    }
    elsif($color eq "PURPLE")
    {
        @color_array = (0x99/256.0, 0x66/256.0,1);
    }
    elsif($color eq "BLACK")
    {
        @color_array = (0,0,0);
    }
    elsif($color eq "WHITE")
    {
        @color_array = (1,1,1);
    }
    elsif($color =~ m/([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})/)
    {
        @color_array = (hex($1)/256.0,hex($2)/256.0,hex($3)/256.0);
    }
    else
    {
        @color_array = (0,0,0);
    }
    
    return \@color_array;
}



#+----------------------------------------------------------------------------
#|
#| FUNCTION: drawLine()
#|
#| DESCRIPTION:
#|   Draws a line shape with x and y coordinates starting from the upper
#|   left hand corner of the document.
#|   
#|   Shape properties:
#|      id               - Unique ID to associate with the shape.
#|      line-color       - The color to apply to the line in HTML format.
#|      line-pattern     - The pattern to associate with the line. See
#|                         Visio for a list of line patterns.
#|      line-weight      - The weight (1-9) to apply to the line.
#|      x1               - The start x coordinate in inches where line begins.
#|      x2               - The end x coordinate in inches where line ends.
#|      y1               - The start y coordinate in inches where line begins.
#|      y2               - The end y coordinate in inches where line ends.
#|      arrow-begin      - The style arrow to apply to beginning of the line
#|      arrow-end        - The style arrow to apply to end of line.
#|      text             - The text label to apply to the line.
#|      font-color       - The color to apply to the font.
#|
#| PARAMETERS:
#|   $self     (I) - The pointer to the blessed class instance.
#|   $propsRef (I) - The properties associated with the line. See
#|                   the description for a list of shape properties.
#|
#| RETURNS:
#|   The ID of the shape.
#|     
#+----------------------------------------------------------------------------
sub drawLine
{
    my ($self,$propsRef) = @_;
    
    if(!defined($propsRef))
    {
        die("Properties reference passed to cairo::drawLine is undefined\n");
    }
    
    my $type = ref($propsRef);
    if($type ne 'REF' && $type ne 'HASH')
    {
        die("Properties reference passed to cairo::drawLine is invalid\n");
    }
    
    if(!defined($propsRef->{"id"}))
    {
       $propsRef->{"id"} = $self->anyId();
    }
    
    my $im = ${$self->{IMAGE}};
    
    $propsRef->{"line-color"} = translateColor($propsRef->{"line-color"});
    $propsRef->{"font-color"} = translateColor($propsRef->{"font-color"});
    #$propsRef->{"arrow-begin-color"} = translateColor($propsRef->{"arrow-begin-color"});
    #$propsRef->{"arrow-end-color"} = translateColor($propsRef->{"arrow-end-color"});
    
    if(!defined($propsRef->{"font-size"}))
    {
        $propsRef->{"font-size"} = 10;
    }
    
    
    if(!defined($propsRef->{"line-pattern"}))
    {
       $propsRef->{"line-pattern"} = 0;
    }
    
    if(!defined($propsRef->{"arrow-begin"}))
    {
        $propsRef->{"arrow-begin"} = 0;
    }
    
    if(!defined($propsRef->{"arrow-begin-size"}))
    {
        $propsRef->{"arrow-begin-size"} = 1;
    }
    
    
    
    if(!defined($propsRef->{"arrow-end"}))
    {
        $propsRef->{"arrow-end"} = 0;
    }
    
    if(!defined($propsRef->{"arrow-end-size"}))
    {
        $propsRef->{"arrow-end-size"} = 1;
    }
    
    if(!defined($propsRef->{"text"}))
    {
       $propsRef->{"text"} = "";
    }
   
    if(!defined($propsRef->{"line-weight"}))
    {
         $propsRef->{"line-weight"} = 1;
    }
    
    my $a;
    if($propsRef->{"line-pattern"} == 1)
    {
        $a = cairolib::new_doubleArray(2);
        cairolib::doubleArray_setitem($a, 0, 1);
        cairolib::doubleArray_setitem($a, 1, 1);
        $im->set_dash($a, 2, 0.0);
        cairolib::delete_doubleArray($a);
    }
    elsif($propsRef->{"line-pattern"} == 2)
    {
        $a = cairolib::new_doubleArray(2);
        cairolib::doubleArray_setitem($a, 0, 2);
        cairolib::doubleArray_setitem($a, 1, 2);
        $im->set_dash($a, 2, 0.0);
        cairolib::delete_doubleArray($a);
    }
    elsif($propsRef->{"line-pattern"} == 3)
    {
        $a = cairolib::new_doubleArray(2);
        cairolib::doubleArray_setitem($a, 0, 3);
        cairolib::doubleArray_setitem($a, 1, 3);
        $im->set_dash($a, 2, 0.0);
        cairolib::delete_doubleArray($a);

    }
    elsif($propsRef->{"line-pattern"} == 4)
    {  
        $a = cairolib::new_doubleArray(2);
        cairolib::doubleArray_setitem($a, 0, 4);
        cairolib::doubleArray_setitem($a, 1, 4);
        $im->set_dash($a, 2, 0.0);
        cairolib::delete_doubleArray($a);
    }

    my $x1 = $propsRef->{"x1"};
    my $x2 = $propsRef->{"x2"};
    my $y1 = $propsRef->{"y1"};
    my $y2 = $propsRef->{"y2"};
    
    # Now calculate the position of any arrows if it is necessary
    # to display them.
    my $x = $x2 - $x1;
    my $y = $y2 - $y1;
    my $z = sqrt(abs($x*$x) + abs($y*$y));
    
    # The 57.2957795 is used to convert radians to degrees
    my $alpha = asin($y/$z) * 57.2957795;
    my $beta = 90 - $alpha;
    
    if($x1 > $x2)
    {
        my $tmp = $x1;
        $x1 = $x2;
        $x2 = $x1;
        $beta = -$beta;
        $alpha = 360 - $alpha;
    }
    
    if($y1 > $y2)
    {
        my $tmp = $y1;
        $y1 = $y2;
        $y2 = $y1;
    }
    
    $im->move_to($propsRef->{"x1"}, $propsRef->{"y1"});
    
    $im->set_source_rgb($propsRef->{"line-color"}->[0], $propsRef->{"line-color"}->[1], $propsRef->{"line-color"}->[2]);
    
    
    $im->set_line_width($propsRef->{"line-weight"});
    $im->line_to($propsRef->{"x2"}, $propsRef->{"y2"});
    
    $im->stroke();
    
    # Now clear the dash pattern
    $a = cairolib::new_doubleArray(2);
    cairolib::doubleArray_setitem($a, 0, 0);
    cairolib::doubleArray_setitem($a, 1, 0);
    $im->set_dash($a, 0, 0.0);
    cairolib::delete_doubleArray($a);
    
    if($propsRef->{"arrow-begin"} > 0)
    {
        $self->drawArrowHead({"x" => $propsRef->{"x1"},
                              "y" => $propsRef->{"y1"},
                              "angle" => 360 - $beta,
                              "arrow-type" => $propsRef->{"arrow-begin"},
                              "arrow-size" => $propsRef->{"arrow-begin-size"},
                              "arrow-color" => $propsRef->{"arrow-begin-color"}});
    }
    
    if($propsRef->{"arrow-end"} > 0)
    {
        $self->drawArrowHead({"x" => $propsRef->{"x2"},
                              "y" => $propsRef->{"y2"},
                              "arrow-type" => $propsRef->{"arrow-end"},
                              "angle" => 180 - $beta,
                              "arrow-size" => $propsRef->{"arrow-end-size"},
                              "arrow-color" => $propsRef->{"arrow-end-color"}});
    }

=pod

    if($propsRef->{"text"} ne "")
    {
       $self->drawText({"x" => $propsRef->{"x1"} + $x/2,
                        "y" => $propsRef->{"y1"} + $y/2,
                        "text" => $propsRef->{"text"},
                        "font-color" => $propsRef->{"font-color"},
                        "angle" => $alpha,
                        "font-size" => $propsRef->{"font-size"}});
    }
=cut

    return $propsRef->{"id"};
}


#+----------------------------------------------------------------------------
#|
#| FUNCTION: drawText()
#|
#| DESCRIPTION:
#|   Draws a text block shape with x and y coordinates starting from the upper
#|   left hand corner of the document.
#|   
#|   Shape properties:
#|      id               - Unique ID to associate with the shape.
#|      font-color       - The color to apply to the text in HTML format.
#|      x                - The x coordinate in pixels where the line begins
#|      y                - The y coordinate in pixels where the line begins.
#|      text             - The text label to apply to the text block.
#|
#| PARAMETERS:
#|   $self     (I) - The pointer to the blessed class instance.
#|   $propsRef (I) - The properties associated with the text block. See
#|                   the description for a list of shape properties.
#|
#| RETURNS:
#|   The ID of the shape.
#|     
#+----------------------------------------------------------------------------
sub drawText
{
    my ($self,$propsRef) = @_;
    
    if(!defined($propsRef))
    {
        die("Properties reference passed to cairo::drawText is undefined\n");
    }
    
    my @bounds;
    my $type = ref($propsRef);
    if($type ne 'REF' && $type ne 'HASH')
    {
        die("Properties reference passed to cairo::drawText is invalid\n");
    }
    
    my $im = ${$self->{IMAGE}};
    
    if(!defined($propsRef->{"id"}))
    {
       $propsRef->{"id"} = $self->anyId();
    }
    
    defaultProperty($propsRef, "font-color", "#000000");
    $propsRef->{"font-color"} = translateColor($propsRef->{"font-color"});
    
    defaultProperty($propsRef, "width", 0);
    
    
    if(!defined($propsRef->{"font-size"}))
    {
        $propsRef->{"font-size"} = 10;
    }
    
    $propsRef->{"font-size"} += 3;
    
    if(!defined($propsRef->{"angle"}))
    {
        $propsRef->{"angle"} = 0;
    }
    
    if(!defined($propsRef->{"text-anchor"}))
    {
        $propsRef->{"text-anchor"} = "start";
    }
    
    if(!defined($propsRef->{"text-orientation"}))
    {
        $propsRef->{"text-orientation"} = "horizontal";
    }
    
    #$self->drawRect({"x" => $propsRef->{"x"},
    #                 "y" => $propsRef->{"y"},
    #                 "width" => $propsRef->{"width"},
    #                 "height" => $propsRef->{"height"},
    #                 "line-color" => "#000000",
    #                 "background-color" => "#FFFFFF"});
                     
    my $text_width;
    my $text_height;
 
    ($text_width, $text_height) = $im->text_extents("$propsRef->{\"text\"}");
    
    if($propsRef->{"text-orientation"} eq "horizontal")
    {
        if($propsRef->{"text-anchor"} eq "start")
        {
            $im->move_to($propsRef->{"x"}, $propsRef->{"y"} + $text_height);
        }
        elsif($propsRef->{"text-anchor"} eq "middle")
        {
            $im->move_to($propsRef->{"x"} + $propsRef->{"width"}/2 - ($text_width/2), $propsRef->{"y"} + $text_height);
        }
        else
        {
            $im->move_to($propsRef->{"x"} + $propsRef->{"width"} - $text_width, $propsRef->{"y"} + $text_height);
        }
    }
    else
    {
        #die("Do I get here?\n");
        if($propsRef->{"text-anchor"} eq "middle")
        {
            $im->move_to($propsRef->{"x"}, $propsRef->{"y"} + $text_height/2);
        }
        else
        {
            $im->move_to($propsRef->{"x"}, $propsRef->{"y"} + $text_height);
        }
    }
    
    $im->set_source_rgb($propsRef->{"font-color"}->[0], $propsRef->{"font-color"}->[1], $propsRef->{"font-color"}->[2]);
    
    $im->set_font_size($propsRef->{"font-size"});
    
    $im->show_text($propsRef->{"text"});
    $im->stroke();
    
    
    
=pod
    if($propsRef->{"text-orientation"} eq "horizontal")
    {
        my $textWidth = getTextWidth($propsRef->{"text"}, $propsRef->{"font-size"}, "/usr/share/fonts/bitstream-vera/VeraMono.ttf");
        
        if(defined($propsRef->{"width"}) && ($textWidth > $propsRef->{"width"}))
        {
            my $numchars = ($propsRef->{"width"})/(($propsRef->{"font-size"})/1.7);
            
            if($numchars <= 1)
            {
                $numchars = 1;
            }
            
            $propsRef->{"text"} = substr($propsRef->{"text"}, 0, $numchars);
            $textWidth = $numchars * ($propsRef->{"font-size"}/1.7);
        }
        
        if(defined($propsRef->{"height"}))
        {
            $propsRef->{"y"} += (($propsRef->{"font-size"})/2 + $propsRef->{"height"}/2);
        }
        else
        {
            $propsRef->{"y"} += $propsRef->{"font-size"};
        }
        
        if(!defined($propsRef->{"width"}))
        {
            $propsRef->{"width"} = 0;
        }
        
        if(defined($propsRef->{"text-anchor"}) && defined($propsRef->{"width"}))
        {
            if($propsRef->{"text-anchor"} eq "start")
            {
             
            }
            elsif($propsRef->{"text-anchor"} eq "end")
            { 
                $propsRef->{"x"} = $propsRef->{"x"} + $propsRef->{"width"} - $textWidth;
            }
            elsif($propsRef->{"text-anchor"} eq "middle")
            {
                $propsRef->{"x"} -= ($textWidth/2);
            }
        }
    
        @bounds = $im->stringFT($propsRef->{"font-color"},
                  #"/usr/share/fonts/bitstream-vera/Vera.ttf",
                  "/usr/share/fonts/bitstream-vera/VeraMono.ttf",
                  $propsRef->{"font-size"},
                  -(($propsRef->{"angle"})/57.2957795),
                  $propsRef->{"x"},
                  $propsRef->{"y"},
                  $propsRef->{"text"});
        
        $propsRef->{"bounds"} = \@bounds;
    }
    elsif($propsRef->{"text-orientation"} eq "vertical")
    {
        my $textHeight = length($propsRef->{"text"}) * ($propsRef->{"font-size"}/1.7);
        
        if(defined($propsRef->{"height"}) && ($textHeight > $propsRef->{"height"}))
        {
            my $numchars = ($propsRef->{"height"})/(($propsRef->{"font-size"})/1.7);
            
            if($numchars <= 1)
            {
                $numchars = 1;
            }
            
            $propsRef->{"text"} = substr($propsRef->{"text"}, 0, $numchars);
            $textHeight = $numchars * (($propsRef->{"font-size"})/1.7);
        }
        
        $im->stringUp(gdSmallFont,$propsRef->{"x"},$propsRef->{"y"},$propsRef->{"text"},$propsRef->{"font-color"})
    }
=cut

    
    my %result;
    $result{"id"} = $propsRef->{"id"};
    $result{"bounds"} = \@bounds;
    
    return %result;
}



#+----------------------------------------------------------------------------
#|
#| FUNCTION: drawRect()
#|
#| DESCRIPTION:
#|   Draws a rectangle shape with x and y coordinates starting from the upper
#|   left hand corner of the document.
#|   
#|   Shape properties:
#|      id               - Unique ID to associate with the shape.
#|      line-color       - The color to apply to the line in HTML format or one
#|                         of the default colors (0 - 23). Refer to the new()
#|                         routine for the list of default colors.
#|      background-color - The background color to apply to the shape in HTML
#|                         format or one of the default colors (0-23).
#|      x                - The x coordinate in inches where the line begins
#|      y                - The y coordinate in inches where the line begins.
#|      width            - The width of the rectangle in inches.
#|      height           - The height of the rectangle in inches.
#|      text             - The text label to apply to the rectangle.
#|
#| PARAMETERS:
#|   $self     (I) - The pointer to the blessed class instance.
#|   $propsRef (I) - The properties associated with the rectangle. See
#|                   the description for a list of shape properties.
#|
#| RETURNS:
#|   The ID of the shape.
#|     
#+----------------------------------------------------------------------------
sub drawRect
{
    my ($self,$propsRef) = @_;
    
    if(!defined($propsRef))
    {
        die("Properties reference passed to cairo::drawRect is undefined\n");
    }
    
    my $type = ref($propsRef);
    if($type ne 'REF' && $type ne 'HASH')
    {
        die("Properties reference passed to cairo::drawRect is invalid\n");
    }
    
    my $im = ${$self->{IMAGE}};
    
    if(!defined($propsRef->{"angle"}))
    {
        $propsRef->{"angle"} = 0;
    }
    
    if(!defined($propsRef->{"id"}))
    {
        $propsRef->{"id"} = $self->anyId();
    }
    
    $propsRef->{"line-color"} = translateColor($propsRef->{"line-color"});
    $propsRef->{"background-color"} = translateColor($propsRef->{"background-color"});
    
    
=pod
    if(!defined($propsRef->{"flip-x"}))
    {
        $propsRef->{"flip-x"} = 0;
    }
    
    if(!defined($propsRef->{"flip-y"}))
    {
        $propsRef->{"flip-y"} = 0;
    }
=cut
    
    if(!defined($propsRef->{"text"}))
    {
        $propsRef->{"text"} = "";
    }
    
    
    if(!defined($propsRef->{"font-height"}))
    {
        $propsRef->{"font-height"} = 0.05;
    }
    
    if(!defined($propsRef->{"text-orientation"}))
    {
        $propsRef->{"text-orientation"} = "horizontal";
    }
    
=pod
    if(!defined($propsRef->{"line-pattern"}) || $propsRef->{"line-pattern"} == 1)
    {
        $im->setStyle(gdAntiAliased);
    }
    elsif($propsRef->{"line-pattern"} == 2)
    {
        $im->setStyle(gdAntiAliased, gdAntiAliased, gdAntiAliased, gdAntiAliased, gdAntiAliased,
                      gdTransparent,gdTransparent, gdTransparent);
    }
    elsif($propsRef->{"line-pattern"} == 3)
    {
        $im->setStyle(gdAntiAliased, gdAntiAliased,
                      gdTransparent,gdTransparent);
    }
    elsif($propsRef->{"line-pattern"} == 4)
    {
        $im->setStyle(gdAntiAliased, gdAntiAliased,
                      gdTransparent,gdTransparent, gdTransparent,
                      gdAntiAliased, gdAntiAliased, gdAntiAliased, gdAntiAliased, gdAntiAliased, gdAntiAliased, gdAntiAliased,gdAntiAliased,
                      gdTransparent, gdTransparent, gdTransparent);
    }
=cut
    
=pod
    # make a polygon
    my $poly = new GD::Polygon;
    $poly->addPt($propsRef->{"x"},
                 $propsRef->{"y"});
                 
    $poly->addPt($propsRef->{"x"} + $propsRef->{"width"},
                 $propsRef->{"y"});
    
    if($propsRef->{"break-right"})
    {
       $poly->addPt($propsRef->{"x"} + $propsRef->{"width"},
                    $propsRef->{"y"} + (0.2 * $propsRef->{"height"}));
       
       $poly->addPt($propsRef->{"x"} + $propsRef->{"width"} + 5,
                    $propsRef->{"y"} + (0.2 * $propsRef->{"height"}));
       
       $poly->addPt($propsRef->{"x"} + $propsRef->{"width"} - 5,
                    $propsRef->{"y"} + (0.8 * $propsRef->{"height"}));
       
       $poly->addPt($propsRef->{"x"} + $propsRef->{"width"},
                    $propsRef->{"y"} + (0.8 * $propsRef->{"height"}));
    }
    
    $poly->addPt($propsRef->{"x"} + $propsRef->{"width"},
                     $propsRef->{"y"} + $propsRef->{"height"});
    
    $poly->addPt($propsRef->{"x"},
                     $propsRef->{"y"} + $propsRef->{"height"});
    
    if($propsRef->{"break-left"})
    {
       $poly->addPt($propsRef->{"x"},
                    $propsRef->{"y"} + (0.8 * $propsRef->{"height"}));
       
       $poly->addPt($propsRef->{"x"} - 5,
                    $propsRef->{"y"} + (0.8 * $propsRef->{"height"}));
       
       $poly->addPt($propsRef->{"x"} + 5,
                    $propsRef->{"y"} + (0.2 * $propsRef->{"height"}));
       
       $poly->addPt($propsRef->{"x"},
                    $propsRef->{"y"} + (0.2 * $propsRef->{"height"}));
    }
=cut
    $im->set_line_width(1);
    my $rounding = 0;
    if($rounding)
    {
        my $radius = 6;
        my $x0 = $propsRef->{"x"};
        my $y0 = $propsRef->{"y"};
        my $x1 = $x0 + $propsRef->{"width"};
        my $y1 = $y0 + $propsRef->{"height"};
        my $rect_width = $propsRef->{"width"};
        my $rect_height = $propsRef->{"height"};
        
        if ($rect_width/2<$radius)
        {
            if ($rect_height/2<$radius)
            {
                $im->move_to  ($x0, ($y0 + $y1)/2);
                $im->curve_to ($x0 ,$y0, $x0, $y0, ($x0 + $x1)/2, $y0);
                $im->curve_to ($x1, $y0, $x1, $y0, $x1, ($y0 + $y1)/2);
                $im->curve_to ($x1, $y1, $x1, $y1, ($x1 + $x0)/2, $y1);
                $im->curve_to ($x0, $y1, $x0, $y1, $x0, ($y0 + $y1)/2);
            }
            else
            {
                $im->move_to  ($x0, $y0 + $radius);
                $im->curve_to ($x0 ,$y0, $x0, $y0, ($x0 + $x1)/2, $y0);
                $im->curve_to ($x1, $y0, $x1, $y0, $x1, $y0 + $radius);
                $im->line_to ($x1 , $y1 - $radius);
                $im->curve_to ($x1, $y1, $x1, $y1, ($x1 + $x0)/2, $y1);
                $im->curve_to ($x0, $y1, $x0, $y1, $x0, $y1- $radius);
            }
        }
        else
        {
            if ($rect_height/2<$radius)
            {
                $im->move_to  ($x0, ($y0 + $y1)/2);
                $im->curve_to ($x0 , $y0, $x0 , $y0, $x0 + $radius, $y0);
                $im->line_to ($x1 - $radius, $y0);
                $im->curve_to ($x1, $y0, $x1, $y0, $x1, ($y0 + $y1)/2);
                $im->curve_to ($x1, $y1, $x1, $y1, $x1 - $radius, $y1);
                $im->line_to ($x0 + $radius, $y1);
                $im->curve_to ($x0, $y1, $x0, $y1, $x0, ($y0 + $y1)/2);
            }
            else
            {
                $im->move_to  ($x0, $y0 + $radius);
                $im->curve_to ($x0 , $y0, $x0 , $y0, $x0 + $radius, $y0);
                $im->line_to ($x1 - $radius, $y0);
                $im->curve_to ($x1, $y0, $x1, $y0, $x1, $y0 + $radius);
                $im->line_to ($x1 , $y1 - $radius);
                $im->curve_to ($x1, $y1, $x1, $y1, $x1 - $radius, $y1);
                $im->line_to ($x0 + $radius, $y1);
                $im->curve_to ($x0, $y1, $x0, $y1, $x0, $y1- $radius);
            }
        }
        $im->close_path ();

        $im->set_source_rgb ($propsRef->{"background-color"}->[0], $propsRef->{"background-color"}->[1], $propsRef->{"background-color"}->[2]);
        $im->fill_preserve ();
        $im->set_source_rgb ($propsRef->{"line-color"}->[0], $propsRef->{"line-color"}->[1], $propsRef->{"line-color"}->[2]);
        $im->stroke ();
    }
    else
    {
        $im->set_source_rgb($propsRef->{"background-color"}->[0], $propsRef->{"background-color"}->[1], $propsRef->{"background-color"}->[2]);
        $im->rectangle($propsRef->{"x"},
                       $propsRef->{"y"},
                       $propsRef->{"width"},
                       $propsRef->{"height"});
        $im->fill();
        
        $im->set_source_rgb($propsRef->{"line-color"}->[0], $propsRef->{"line-color"}->[1], $propsRef->{"line-color"}->[2]);
        $im->rectangle($propsRef->{"x"},
                       $propsRef->{"y"},
                       $propsRef->{"width"},
                       $propsRef->{"height"});
        $im->stroke();
    }

    
    if($propsRef->{"text"} ne "")
    {
       my $text = $propsRef->{"text"};
       
       $self->drawText({"x" => $propsRef->{"x"} + $propsRef->{"width"}/2,
                        "y" => $propsRef->{"y"}  + $propsRef->{"height"}/3,
                        "text" => $text,
                        "font-color" => $propsRef->{"font-color"},
                        "font-size" => $propsRef->{"font-size"},
                        "angle" => $propsRef->{"angle"},
                        "width" => $propsRef->{"width"},
                        "height" => $propsRef->{"height"},
                        "text-anchor" => "middle",
                        "text-orientation" => $propsRef->{"text-orientation"}});
    }

    return $propsRef->{"id"};
   
}


#+----------------------------------------------------------------------------
#|
#| FUNCTION: drawEllipse()
#|
#| DESCRIPTION:
#|   Draws an ellipse shape with x and y coordinates starting from the upper
#|   left hand corner of the document.
#|   
#|   Shape properties:
#|      page       - The page that the shape will exist on. Default is
#|                   first page (0)
#|      id         - Unique ID to associate with the shape.
#|      line-color - The color to apply to the line in HTML format or one
#|                   of the default colors (0 - 23). Refer to the new() routine
#|                   for the list of default colors.
#|      x          - The x coordinate in inches where the line begins
#|      y          - The y coordinate in inches where the line begins.
#|      width      - The width of the ellipse in inches.
#|      height     - The height of the ellipse in inches.
#|      text       - The text label to apply to the ellipse.
#|
#|
#| PARAMETERS:
#|   $self (I) - The pointer to the blessed class instance.
#|
#| RETURNS:
#|   The ID of the ellipse.
#|     
#+----------------------------------------------------------------------------
sub drawEllipse
{
    my ($self,$propsRef) = @_;
    
    if(!defined($propsRef))
    {
        die("Properties reference passed to cairo::drawEllipse is undefined\n");
    }
    
    if(!defined($propsRef->{"x"}) ||
       !defined($propsRef->{"y"}) || 
       !defined($propsRef->{"width"}) ||
       !defined($propsRef->{"height"}))
    {
        die("x, y, width, height are required properties for cairo::drawEllipse\n");
    }
    
    my $type = ref($propsRef);
    if($type ne 'REF' && $type ne 'HASH')
    {
        die("Properties reference passed to cairo::drawEllipse is invalid\n");
    }
    
    my $im = ${$self->{IMAGE}};
    
    # Default any properties that are not defined
    defaultProperty($propsRef, "id", $self->anyId());
    defaultProperty($propsRef, "line-color", "#000000");
    defaultProperty($propsRef, "line-pattern", 1);
    defaultProperty($propsRef, "font-color", "#000000");
    defaultProperty($propsRef, "background-color", "#FFFFFF");
    defaultProperty($propsRef, "font-size", 10);
    defaultProperty($propsRef, "text", "");
    defaultProperty($propsRef, "comment", "");
    
    $propsRef->{"line-color"} = translateColor($propsRef->{"line-color"});
    $propsRef->{"background-color"} = translateColor($propsRef->{"background-color"});
    $propsRef->{"font-color"} = translateColor($propsRef->{"font-color"});
    
    $im->set_line_width(0.6);
    
    $im->save();
    $im->translate($propsRef->{"x"} + $propsRef->{"width"} / 2.,
                   $propsRef->{"y"} + $propsRef->{"height"} / 2.);
    $im->scale(1. * ($propsRef->{"width"} / 2.), 1. * ($propsRef->{"height"} / 2.));
    $im->arc(0., 0., 1., 0., 2 * 3.1457);
    
    $im->set_source_rgb($propsRef->{"background-color"}->[0], $propsRef->{"background-color"}->[1], $propsRef->{"background-color"}->[2]);
    $im->fill_preserve();
    $im->restore();
    
    $im->set_source_rgb($propsRef->{"line-color"}->[0], $propsRef->{"line-color"}->[1], $propsRef->{"line-color"}->[2]);
    $im->stroke();
    
    if($propsRef->{"text"} ne "")
    {
       my $text = $propsRef->{"text"};
       
       $self->drawText({"x" => $propsRef->{"x"},
                        "y" => $propsRef->{"y"} + $propsRef->{"height"}/3,
                        "text" => $text,
                        #"font-color" => $propsRef->{"font-color"},
                        "font-size" => $propsRef->{"font-size"},
                        "angle" => $propsRef->{"angle"},
                        "width" => $propsRef->{"width"},
                        "height" => $propsRef->{"height"},
                        "text-anchor" => "middle",
                        "text-orientation" => $propsRef->{"text-orientation"}});
    }
    
    
    return $propsRef->{"id"};
}



sub drawArrowHead
{
    my ($self, $propsRef) = @_;
    
    my $im = ${$self->{IMAGE}};
    
    # Default any properties that are not defined
    defaultProperty($propsRef, "arrow-type", 2);
    defaultProperty($propsRef, "arrow-size", 2);
    defaultProperty($propsRef, "arrow-color", 0x000000);
    defaultProperty($propsRef, "angle", 0);
    defaultProperty($propsRef, "x", 0);
    defaultProperty($propsRef, "y", 0);
    
    $propsRef->{"arrow-color"} = translateColor($propsRef->{"arrow-color"});
    
    my $alpha = 90 + $propsRef->{"angle"};
    my $beta = 90 - $alpha;
    my $x = $propsRef->{"x"};
    my $y = $propsRef->{"y"};
    
    if($propsRef->{"arrow-type"} == 2)
    {
        $im->new_path();
        my $xoff = 4 * ($propsRef->{"arrow-size"}) * sin(($beta-35)/57.2957795);
        my $yoff = 4 * ($propsRef->{"arrow-size"}) * cos(($beta-35)/57.2957795);
        
        $im->move_to($x, $y);
        $im->line_to($x + $xoff, $y + $yoff);
            
        $xoff = 4 * ($propsRef->{"arrow-size"}) * cos(($alpha-35)/57.2957795);
        $yoff = 4 * ($propsRef->{"arrow-size"}) * sin(($alpha-35)/57.2957795);
        
        $im->line_to($x + $xoff, $y + $yoff);
        $im->line_to($x, $y);
        
        $im->set_source_rgb($propsRef->{"arrow-color"}->[0], $propsRef->{"arrow-color"}->[1], $propsRef->{"arrow-color"}->[2]);
        $im->fill_preserve();
        $im->stroke();
        
    }
    

}



#+----------------------------------------------------------------------------
#|
#| FUNCTION: create()
#|
#| DESCRIPTION:
#|   Generates an the cairo image output.
#|
#| PARAMETERS:
#|   $self (I) - The pointer to the blessed class instance.
#|
#| RETURNS:
#|   The binary output of the cairo image.
#|   
#+----------------------------------------------------------------------------
sub create
{
    my $self = shift;
    my $output = $_[0];
   
    my $im = ${$self->{IMAGE}};
    
    $im->write_to_png($output, ${$self->{WIDTH}}, ${$self->{HEIGHT}});
}

1